package cc.rengu.oltp.service.realize.impl;

import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.DstTxnAuthCfgMapper;
import cc.rengu.oltp.service.common.dao.SrcChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstTxnAuthCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SrcChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.ChannelService;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 交易渠道及支付通道检查服务实现类
 * Created by 王成 on 2020/2/10
 */
public class ChannelServiceImpl implements ChannelService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public boolean channnelCheck(TxnInfo txnInfo) throws Exception {
        /* Step1：交易渠道状态检查 */
        String srcChannelKey = txnInfo.getSrcTxnAuthCfg().getInstId().trim() + txnInfo.getSrcTxnAuthCfg().getMsgSrcId().trim() + txnInfo.getSrcTxnAuthCfg().getTransChannelId().trim();
        SrcChannelInfo srcChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, srcChannelKey), SrcChannelInfo.class);
        if (null == srcChannelInfo) {
            rglog.info("交易渠道<{}-{}>未单独配置交易权限，使用通用渠道配置进行校验!", txnInfo.getSrcTxnAuthCfg().getMsgSrcId(), txnInfo.getSrcTxnAuthCfg().getTransChannelId());
            srcChannelKey = txnInfo.getSrcTxnAuthCfg().getInstId().trim() + txnInfo.getSrcTxnAuthCfg().getMsgSrcId().trim() + "*";
            srcChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, srcChannelKey), SrcChannelInfo.class);
            if (null == srcChannelInfo) {
                SrcChannelInfoMapper srcChannelInfoMapper = new SrcChannelInfoMapperImpl();
                srcChannelInfo = srcChannelInfoMapper.selectSrcChannelInfoByPrimaryKey(txnInfo.getSrcTxnAuthCfg().getInstId().trim(), txnInfo.getSrcTxnAuthCfg().getMsgSrcId().trim(), txnInfo.getSrcTxnAuthCfg().getTransChannelId().trim());
            }
        }
        if (null == srcChannelInfo || !srcChannelInfo.getTransChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("交易渠道<{}-{}>的细分渠道<{}-{}>未配置或已停用！", txnInfo.getSrcTxnAuthCfg().getMsgSrcId(), (null == srcChannelInfo) ? "" : srcChannelInfo.getSrcChannelName(), txnInfo.getSrcTxnAuthCfg().getTransChannelId(), (null == srcChannelInfo) ? "" : srcChannelInfo.getTransChannelName());
            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
        }
        /* Step2：渠道交易权限检查 */
        if (!txnInfo.getSrcTxnAuthCfg().getSupportFlag().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("不支持此交易<{}>", txnInfo.getTxnKey());
            throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
        }
        /* Step3：检查交易是否在交易渠道支持的时间范围内 */
        String currentTime = DateUtil.getCurrentTime();
        String supportBeginTime = getSupportBeginTime(txnInfo.getSrcTxnAuthCfg().getSupportBeginTime(), srcChannelInfo.getBizStartTime());
        String supportEndTime = getSupportEndTime(txnInfo.getSrcTxnAuthCfg().getSupportEndTime(), srcChannelInfo.getBizEndTime());
        if ((!"*".equals(supportBeginTime) && Integer.parseInt(supportBeginTime) > Integer.parseInt(currentTime)) ||
                (!"*".equals(supportEndTime) && Integer.parseInt(supportEndTime) < Integer.parseInt(currentTime))) {
            rglog.error("交易<{}>超出渠道<{}-{}>支持的时间范围:<{}-{}>", txnInfo.getTxnKey(), srcChannelInfo.getSrcChannelId(), srcChannelInfo.getSrcChannelName(), supportBeginTime, supportEndTime);
            throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
        }
        /* Step4：支付通道状态检查 */
        if (null != txnInfo.getChannelCallCfgList() && !txnInfo.getChannelCallCfgList().isEmpty()) {
            /* Step4.1：过滤掉不需要进行通道校验控制的通道 */
            List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item ->
                    !item.getCallChannelId().equals("LOCAL") && AppParamConstant.YES.equals(item.getRecordStatus())).collect(Collectors.toList());
            /* Step4.2：内部通道状态及交易权限不控制 */
            for (ChannelCallCfg channelCallCfg : channelCallCfgList) {
                if (ChannelEnum.ACCT.getChannelType().equals(channelCallCfg.getCallChannelId()) || ChannelEnum.MOMP.getChannelType().equals(channelCallCfg.getCallChannelId()) || ChannelEnum.IGRT.getChannelType().equals(channelCallCfg.getCallChannelId())) {
                    continue;
                }
                /* Step4.3：支付通道状态检查 */
                String dstChannelKey = channelCallCfg.getInstId().trim() + channelCallCfg.getCallChannelId().trim();
                DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
                if (null == dstChannelInfo) {
                    DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
                    dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(channelCallCfg.getInstId().trim(), channelCallCfg.getCallChannelId().trim());
                }
                if (null == dstChannelInfo || !dstChannelInfo.getDstChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
                    rglog.error("支付渠道<{}-{}>未配置或已停用！", channelCallCfg.getCallChannelId(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
                    throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
                }
                /* Step4.4：支付通道权限检查 */
                String dstChannelAuthKey = channelCallCfg.getInstId().trim() + channelCallCfg.getCallChannelId().trim() + channelCallCfg.getCallChannelTxn().trim();
                DstTxnAuthCfg dstTxnAuthCfg = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_TXN_CACHE, dstChannelAuthKey), DstTxnAuthCfg.class);
                if (null == dstTxnAuthCfg) {
                    DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
                    dstTxnAuthCfg = dstTxnAuthCfgMapper.selectDstTxnAuthCfgByPrimaryKey(channelCallCfg.getInstId().trim(), channelCallCfg.getCallChannelId().trim(), channelCallCfg.getCallChannelTxn().trim());
                }
                if (null == dstTxnAuthCfg || !dstTxnAuthCfg.getSupportFlag().equalsIgnoreCase(AppParamConstant.YES)) {
                    rglog.error("支付通道<{}-{}>不支持此交易<{}>，通道交易码:<{}>", dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), channelCallCfg.getCallChannelTxn(), txnInfo.getTxnKey());
                    throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
                }
                /* Step4.5：检查交易是否在支持时间范围内 */
                String dstSupportBeginTime = getSupportBeginTime(dstTxnAuthCfg.getSupportBeginTime(), dstChannelInfo.getBizStartTime());
                String dstSupportEndTime = getSupportEndTime(dstTxnAuthCfg.getSupportEndTime(), dstChannelInfo.getBizEndTime());
                if ((!"*".equals(dstSupportBeginTime) && Integer.parseInt(dstSupportBeginTime) > Integer.parseInt(currentTime)) ||
                        (!"*".equals(dstSupportEndTime) && Integer.parseInt(dstSupportEndTime) < Integer.parseInt(currentTime))) {
                    rglog.error("交易<{}>超出通道<{}-{}>支持的时间范围:<{}-{}>", txnInfo.getTxnKey(), dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), dstSupportBeginTime, dstSupportEndTime);
                    throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
                }
            }
        }
        return true;
    }

    /**
     * 获取渠道或者通道最晚支持交易的时间
     *
     * @param txnSupportBeginTime     交易配置支持的开始时间
     * @param channelSupportBeginTime 渠道或者通道配置的开始时间
     * @return 交易支持的最晚时间
     */
    private String getSupportBeginTime(String txnSupportBeginTime, String channelSupportBeginTime) {
        if ("*".equals(txnSupportBeginTime)) {
            if (!"*".equals(channelSupportBeginTime)) {
                return txnSupportBeginTime;
            }
        } else {
            if ("*".equals(channelSupportBeginTime)) {
                return channelSupportBeginTime;
            } else {
                return (Integer.parseInt(txnSupportBeginTime) > Integer.parseInt(channelSupportBeginTime)) ? txnSupportBeginTime : channelSupportBeginTime;
            }
        }
        return txnSupportBeginTime;
    }

    /**
     * 获取渠道或者通道最早截止交易的时间
     *
     * @param txnSupportEndTime     交易配置支持的截止时间
     * @param channelSupportEndTime 渠道或者通道配置的截止时间
     * @return 交易截止的最早时间
     */
    private String getSupportEndTime(String txnSupportEndTime, String channelSupportEndTime) {
        if ("*".equals(txnSupportEndTime)) {
            if (!"*".equals(channelSupportEndTime)) {
                return txnSupportEndTime;
            }
        } else {
            if ("*".equals(channelSupportEndTime)) {
                return txnSupportEndTime;
            } else {
                return (Integer.parseInt(txnSupportEndTime) < Integer.parseInt(channelSupportEndTime)) ? txnSupportEndTime : channelSupportEndTime;
            }
        }
        return txnSupportEndTime;
    }
}
